package com.doodle.common.utils;

import android.content.Context;
import android.os.SystemClock;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;

// This class aggregates three gesture detectors: GestureDetector,
// ScaleGestureDetector, and DownUpDetector.
public class GestureRecognizer {
	
    private static final String TAG = "GestureRecognizer";

    public interface Listener {
        boolean onSingleTapUp(float x, float y);
        boolean onSingleTapUpConfirmed(float x, float y);
        boolean onDoubleTap(float x, float y);
        boolean onScroll(float dx, float dy, float totalX, float totalY);
        boolean onFling(float velocityX, float velocityY);
        boolean onScaleBegin(float focusX, float focusY);
        boolean onScale(float focusX, float focusY, float scale);
        boolean onDoubleTapEvent(MotionEvent e);
        void onScaleEnd();
        void onDown(float x, float y);
        void onUp();
        void onLongPress(float x, float y);
    }

    private final GestureDetector mGestureDetector;
    private final ScaleGestureDetector mScaleDetector;
    private final DownUpDetector mDownUpDetector;
    private final Listener mListener;
    
    private boolean mScaling = false;
	private boolean mFakeScale = false;

    public GestureRecognizer(Context context, Listener listener) {
        mListener = listener;
        mGestureDetector = new GestureDetector(context, new GestureListenerProxy(),
                null, true /* ignoreMultitouch */);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListenerProxy());
        mDownUpDetector = new DownUpDetector(new DownUpListenerProxy());
    }

    public void onTouchEvent(MotionEvent event) {
        int pointCnt = event.getPointerCount();
        if (pointCnt > 1) {
        	if (!mScaling) {
            	float focusX = (event.getX(0) + event.getX(1)) * 0.5f;
            	float focusY = (event.getY(0) + event.getY(1)) * 0.5f;
        		if (mFakeScale) {
        			mListener.onScale(focusX, focusY, 1.0f);
        		} else {
                	mFakeScale = true;
                	mListener.onScaleBegin(focusX, focusY);
        		}
        	}
        } else {
        	if (mFakeScale) {
        		mFakeScale = false;
        		mListener.onScaleEnd();
        	}
        }
        mGestureDetector.onTouchEvent(event);
        mScaleDetector.onTouchEvent(event);
        mDownUpDetector.onTouchEvent(event);
    }
    
    /**
     * 2014.8.25
     * Forbid Zoom by (double-click-->move)
     * author guanrui for Painter
     */
    public void onNormalTouchEvent(MotionEvent event) {
        int pointCnt = event.getPointerCount();
        if (pointCnt > 1) {
        	if (!mScaling) {
            	float focusX = (event.getX(0) + event.getX(1)) * 0.5f;
            	float focusY = (event.getY(0) + event.getY(1)) * 0.5f;
        		if (mFakeScale) {
        			mListener.onScale(focusX, focusY, 1.0f);
        		} else {
                	mFakeScale = true;
                	mListener.onScaleBegin(focusX, focusY);
        		}
        	}
        	mScaleDetector.onTouchEvent(event);
        } else {
        	if (mFakeScale) {
        		mFakeScale = false;
        		mListener.onScaleEnd();
        	}
        }
        mGestureDetector.onTouchEvent(event);
        mDownUpDetector.onTouchEvent(event);
    }

    public boolean isDown() {
        return mDownUpDetector.isDown();
    }

    public void cancelScale() {
        long now = SystemClock.uptimeMillis();
        MotionEvent cancelEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
        mScaleDetector.onTouchEvent(cancelEvent);
        cancelEvent.recycle();
    }

    private class GestureListenerProxy implements OnGestureListener, OnDoubleTapListener {
    	
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return mListener.onSingleTapUp(e.getX(), e.getY());
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            return mListener.onDoubleTap(e.getX(), e.getY());
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy) {
            return mListener.onScroll(dx, dy, e2.getX() - e1.getX(), e2.getY() - e1.getY());
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return mListener.onFling(velocityX, velocityY);
        }

		@Override
		public boolean onSingleTapConfirmed(MotionEvent e) {
			return mListener.onSingleTapUpConfirmed(e.getX(), e.getY());
		}

		@Override
		public void onLongPress(MotionEvent e) {
			mListener.onLongPress(e.getX(), e.getY());
		}
		
		@Override
		   public boolean onDoubleTapEvent(MotionEvent e) {
            return mListener.onDoubleTapEvent(e);
        }

		@Override
		public boolean onDown(MotionEvent e) {
			return false;
		}

		@Override
		public void onShowPress(MotionEvent e) {
		}
    }

    private class ScaleListenerProxy implements ScaleGestureDetector.OnScaleGestureListener {
    	
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
        	if (mFakeScale) {
        		mFakeScale = false;
        		mScaling = true;
        		mListener.onScale(detector.getFocusX(), detector.getFocusY(), 1.0f);
        		return true;
        	}
        	mScaling = true;
            return mListener.onScaleBegin(detector.getFocusX(), detector.getFocusY());
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            return mListener.onScale(detector.getFocusX(),
                    detector.getFocusY(), detector.getScaleFactor());
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
        	mScaling = false;
        	mFakeScale = false;
            mListener.onScaleEnd();
        }
    }

    private class DownUpListenerProxy implements DownUpDetector.DownUpListener {
    	
        @Override
        public void onDown(MotionEvent e) {
            mListener.onDown(e.getX(), e.getY());
        }

        @Override
        public void onUp(MotionEvent e) {
            mListener.onUp();
        }
    }
}
 